package br.edu.ufcg.dsc.sig.geointerest;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import br.edu.ufcg.dsc.sig.geointerest.gui.client.POI;
import br.edu.ufcg.dsc.sig.geointerest.gui.client.QueryObject;

public class GeoInterestFacadeImpl implements GeoInterestFacade {

	public POI addPOI(POI poi) {

		PreparedStatement pr = null;
		String coordenada = "POINT(" + poi.getLatitude() + " " + poi.getLongitude() + ")";

		try {
			pr = ConexaoBD.getConnection().prepareStatement(BDConstantes.inserirPOI);
			pr.setString(1, poi.getNome());
			pr.setString(2, poi.getEndereco());
			pr.setString(3, poi.getDono());
			pr.setString(4, poi.getTipo());
			pr.setString(5, poi.getDescricao());
			pr.setString(6, poi.getTelefone());
			pr.setString(7, coordenada);
			pr.setInt(8, -1);

			pr.executeUpdate();

			pr.close();
			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return poi;
	}

	public void editPOI(POI poi) {

		PreparedStatement pr = null;
		String coordenada = "POINT(" + poi.getLatitude() + " " + poi.getLongitude() + ")";

		try {

			pr = ConexaoBD.getConnection().prepareStatement(BDConstantes.editarPOI);
			pr.setString(1, poi.getNome());
			pr.setString(2, poi.getEndereco());
			pr.setString(3, poi.getDono());
			pr.setString(4, poi.getTipo());
			pr.setString(5, poi.getDescricao());
			pr.setString(6, poi.getTelefone());
			pr.setString(7, coordenada);
			pr.setInt(8, -1);
			pr.setInt(9, Integer.parseInt(poi.getId()));

			pr.executeUpdate();

			pr.close();
			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}

	public List<POI> getAllPOIs() {

		PreparedStatement pr = null;
		List<POI> listaPOIs = new LinkedList<POI>();

		try {

			pr = ConexaoBD.getConnection().prepareStatement(BDConstantes.recuperarTodosPOI);
			ResultSet rs = pr.executeQuery();

			while( rs.next() ) {

				POI p = new POI();

				String coordenadas = rs.getString(1);
				double[] coordenadasArr = getCoordenada(coordenadas);

				p.setId(rs.getString("srid"));
				p.setLatitude(coordenadasArr[0]);
				p.setLongitude(coordenadasArr[1]);
				p.setNome(rs.getString("nome"));
				p.setDono(rs.getString("dono"));
				p.setEndereco(rs.getString("endereco"));
				p.setTipo(rs.getString("tipo"));
				p.setDescricao(rs.getString("descricao"));
				p.setTelefone(rs.getString("telefone"));

				p.setComentarios(getComentario(p.getId()));
				p.setNota(getNota(p.getId()));

				listaPOIs.add(p);
			}

			pr.close();
			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}	

		return listaPOIs;

	}

	public void removePOI(String id) {

		PreparedStatement pr = null;

		try {

			pr = ConexaoBD.getConnection().prepareStatement(BDConstantes.removerPOI);
			pr.setInt(1, Integer.parseInt(id));

			pr.executeUpdate();
			pr.close();
			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}


	public void darAvaliacao(String poiId, String dono, String comentario, double nota) {

		PreparedStatement pr = null;

		try {

			pr = ConexaoBD.getConnection().prepareStatement(BDConstantes.darAvaliacao);
			pr.setInt(1, Integer.parseInt(poiId));
			pr.setString(2, dono);
			pr.setString(3, comentario);
			pr.setDouble(4, nota);


			pr.executeUpdate();

			pr.close();
			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private Map<String, String> getNota(String id)  {

		PreparedStatement pr = null;
		Map<String, String> notas = new HashMap<String, String>();

		try {
			pr = ConexaoBD.getConnection().prepareStatement(BDConstantes.getNota);
			pr.setInt(1, Integer.parseInt(id));

			ResultSet rs = pr.executeQuery();

			while( rs.next() ) {

				String valor = rs.getString("valor");
				String dono = rs.getString("dono");

				notas.put(dono, valor);
			}

			pr.close();
			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}	

		return notas;

	}

	private Map<String, String> getComentario(String id)  {

		PreparedStatement pr = null;
		Map<String, String> comentarios = new HashMap<String, String>();

		try {
			pr = ConexaoBD.getConnection().prepareStatement(BDConstantes.getComentario);
			pr.setInt(1, Integer.parseInt(id));

			ResultSet rs = pr.executeQuery();

			while( rs.next() ) {

				String comentario = rs.getString("comentario");
				String dono = rs.getString("dono");

				comentarios.put(dono, comentario);
			}

			pr.close();
			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}	

		return comentarios;

	}

	public List<POI> avaliar(QueryObject objetoConsulta) {

		List<POI> listaPOIs = new LinkedList<POI>();

		try {

			ResultSet rs = configurarConsulta(objetoConsulta);

			while( rs.next() ) {

				POI p = new POI();

				String coordenadas = rs.getString(1);
				double[] coordenadasArr = getCoordenada(coordenadas);

				p.setId(rs.getString("srid"));
				p.setLatitude(coordenadasArr[0]);
				p.setLongitude(coordenadasArr[1]);
				p.setNome(rs.getString("nome"));
				p.setDono(rs.getString("dono"));
				p.setEndereco(rs.getString("endereco"));
				p.setTipo(rs.getString("tipo"));
				p.setDescricao(rs.getString("descricao"));
				p.setTelefone(rs.getString("telefone"));
				p.setComentarios(getComentario(p.getId()));
				p.setNota(getNota(p.getId()));

				listaPOIs.add(p);
			}

			ConexaoBD.getConnection().close();
		} catch (Exception e) {
			e.printStackTrace();
		}	

		return listaPOIs;

	}

	private ResultSet configurarConsulta(QueryObject objetoConsulta) throws SQLException {

		String where = "";
		Statement pr = ConexaoBD.getConnection().createStatement();
		
		if (objetoConsulta.getTipo() != null) {
			where += consultaAddTipos(objetoConsulta); 
		} else {
			where += "tipo IS NOT NULL"; 
		}

		if (objetoConsulta.getLatitude() != null && objetoConsulta.getLongitude() != null) {
			String coordenada = "'POINT(" + objetoConsulta.getLatitude() + " " + objetoConsulta.getLongitude() + ")'";
			where += " AND distance(" + coordenada + ", ponto) < " + objetoConsulta.getRaio();
		} else if (objetoConsulta.getArea() != null) {
			where += " AND Contains('POLYGON((" + consultaAddPontosPoligono(objetoConsulta) + "))', ponto)"; 
		}
		
		if (objetoConsulta.getNota() != null) {
			where += " AND " + BDConstantes.getMediaNota + " " + objetoConsulta.getNota();
		}
		
		return pr.executeQuery(BDConstantes.pesquisaPorFiltro + where);

	}

	private String consultaAddPontosPoligono(QueryObject objetoConsulta) {
		String pontos = "";
		for (int i = 0; i < objetoConsulta.getArea().size(); i+=2) {
			pontos += objetoConsulta.getArea().get(i) + " " + objetoConsulta.getArea().get(i+1) + ", ";
		}
		return pontos.substring(0, pontos.length() - 2);
	}

	private String consultaAddTipos(QueryObject objetoConsulta) {
		String tipos = "";
		if (objetoConsulta.getTipo() != null) {
			for (String tipo : objetoConsulta.getTipo()) {
				tipos += " tipo = '" + tipo + "' AND"; 
			}
		}
		return tipos.substring(0,tipos.length() - 3).trim();
	}

	private double[] getCoordenada(String pontoStr)  {

		String pontos = pontoStr.substring(pontoStr.indexOf('(') + 1, pontoStr.indexOf(')'));
		String[] pontosArr = pontos.split(" ");
		double[] coordenadas = { new Double(pontosArr[0]), new Double(pontosArr[1]) };

		return coordenadas;

	}

	public static void main(String[] args) {

		GeoInterestFacadeImpl geo = new GeoInterestFacadeImpl();

		POI poi = new POI();
		poi.setId("2");
		poi.setDescricao("miguel");
		poi.setEndereco("miguel");
		poi.setLatitude(1000.0);
		poi.setLongitude(1000.0);
		poi.setTipo("neneca");
		poi.setDono("miguel");
		poi.setNome("miguel");
		poi.setTelefone("miguel");		

		// geo.addPOI(poi);
		// geo.editPOI(poi);
		// geo.removePOI("2");

		// geo.darAvaliacao("2", "nenecao", "muito bom", 8.0);

		System.out.println(geo.getAllPOIs());
		List lista = new LinkedList<String>();
		lista.add("neneca");
		
		List listaPontos = new LinkedList<Double>();
		
		listaPontos.add(new Double(111110));
		listaPontos.add(new Double(111110));
		
		listaPontos.add(new Double(111110));
		listaPontos.add(new Double(111115));
		
		listaPontos.add(new Double(111115));
		listaPontos.add(new Double(111115));
		
		listaPontos.add(new Double(111115));
		listaPontos.add(new Double(111110));
		
		listaPontos.add(new Double(111110));
		listaPontos.add(new Double(111110));
		System.out.println(geo.avaliar(new QueryObject(null, null, null, listaPontos, null, null)));
	}

}
